package services.impl;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.List;

import play.db.jpa.Blob;

import services.BookApiService;

import com.google.gdata.client.Service.GDataRequest;
import com.google.gdata.client.books.BooksService;
import com.google.gdata.client.books.VolumeQuery;
import com.google.gdata.data.Link;
import com.google.gdata.data.Person;
import com.google.gdata.data.books.VolumeEntry;
import com.google.gdata.data.books.VolumeFeed;
import com.google.gdata.data.dublincore.Creator;
import com.google.gdata.data.dublincore.Description;
import com.google.gdata.data.dublincore.Identifier;
import com.google.gdata.util.ServiceException;

import exceptions.BookNotFoundException;
import exceptions.NotUniqueBookException;

import models.Author;
import models.Book;

public class GoogleBookApiService implements BookApiService {
	
	/**
	 * The name of the server hosting the YouTube GDATA feeds.
	 */
	public static final String BOOKS_GDATA_SERVER = "http://books.google.com";
	/**
	 * The URL of the volumes feed
	 */
	public static final String VOLUMES_FEED = BOOKS_GDATA_SERVER
			+ "/books/feeds/volumes";

	public Book findBookByIsbn(String isbn) throws BookNotFoundException,
			NotUniqueBookException, RemoteException {
		
		try {
			BooksService booksService = new BooksService("grochek-library");
			
			List<VolumeEntry> volumes = listBooksByIsbn(booksService, isbn);
			if (volumes.isEmpty()){
				throw new BookNotFoundException(isbn);
			}
			if (volumes.size() > 1){
				throw new NotUniqueBookException(isbn);
			}
			return toBook(booksService, isbn, volumes.get(0));
			
		} catch (IOException e) {
			throw new RuntimeException(e);
		} catch (ServiceException e) {
			throw new RemoteException("Google API error. Error getting book by isbn"+isbn,e);
		}

	}
	
	public List<VolumeEntry> listBooksByIsbn(BooksService booksService, String isbn) throws IOException, ServiceException {
		VolumeQuery volumeQuery = new VolumeQuery(new URL(VOLUMES_FEED));
		volumeQuery.setMinViewability(VolumeQuery.MinViewability.PARTIAL);
		volumeQuery.setFullTextQuery("isbn:"+isbn);
		VolumeFeed volumeFeed = booksService.query(volumeQuery, VolumeFeed.class);
		
		return volumeFeed.getEntries();	
	}

	private Book toBook(BooksService booksService, String isbn, VolumeEntry volume) throws IOException, ServiceException {
		Book book = new Book();
		for(Creator creator : volume.getCreators()){
			book.authors.add(toAuthor(creator));
		}
		book.isbn = isbn;
		book.name = volume.getTitle().getPlainText();
		StringBuilder descBuffer = new StringBuilder();
		for( Description description : volume.getDescriptions()){
			if (descBuffer.length()>0){
				descBuffer.append("\n");
			}
			descBuffer.append(description.getValue());
			
		}
		book.description = descBuffer.toString();
		
		//TODO 
		Link thumbnailLink = volume.getThumbnailLink();
		GDataRequest request = booksService.createLinkQueryRequest(thumbnailLink);
		request.execute();
		InputStream inStream = request.getResponseStream();
		book.image = new Blob();
		book.image.set(inStream, "PNG");
		request.end();
		return book;
	}

	private Author toAuthor(Creator creator) {
		String names[] = creator.getValue().split(" ");
		Author author = new Author();
		if (names.length > 0){
			author.lastName = names[names.length-1];
		}
		if (names.length > 1){
			author.firstName = names[0];
		}
		return author;
	}
}
